﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using FileManagerSystem.DbInfos;
using FileManagerSystem.Extend;
using FileManagerSystem.Helper;
using FileManagerSystem.Models;
using FileManagerSystem.Service;
using Microsoft.AspNetCore.Mvc;

namespace FileManagerSystem.Controllers
{
    /// <summary>
    /// 文件夹管理接口
    /// </summary>
    public class DirectoryManagerController : ApiBaseController
    {
        /// <summary>
        /// 文件Service对象
        /// </summary>
        [Autowired]
        private IFileService _fileService { get; set; }

        /// <summary>
        /// 映射文件Service对象
        /// </summary>
        [Autowired]
        private IReflectFileService _reflectfileService { get; set; }

        /// <summary>
        /// 目录Service对象
        /// </summary>
        [Autowired]
        private IDirectoryService _directoryService { get; set; }
        #region 目录相关

        /// <summary>
        /// 查询所有目录
        /// </summary>
        /// <param name="search"></param>
        /// <param name="page"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetAllDirectoryInfo(string search, int page = 0, int size = int.MaxValue)
        {
            Expression<Func<DirectoryInf, bool>> whereFunc = x => true;
            if (!search.IsNullOrWhiteSpace())
            {
                whereFunc = whereFunc.And(x => x.Name.Contains(search));
            }
            var result = await _directoryService.FindAllToPage(whereFunc, page, size);
            return Json(result);
        }

        /// <summary>
        /// 获取目录信息
        /// </summary>
        /// <param name="guid">顶级目录唯一标识</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetDirectoryInfo(string guid)
        {
            if (!Guid.TryParse(guid, out Guid id))
                return BadRequest($"传入的guid不合法：{guid}");

            var directoryInf = await _directoryService.FindOne(x => x.Id == id);
            if (directoryInf != null)
            {
                return this.Json(directoryInf);
            }
            return BadRequest("未找到目录");
        }

        /// <summary>
        /// 获取指定顶级目录下所有子文件信息
        /// </summary>
        /// <param name="guid">顶级目录唯一标识</param>
        /// <returns></returns>
        [HttpGet]
        public async Task<IActionResult> GetInDirectoryFilesInfo(string guid)
        {
            if (!Guid.TryParse(guid, out Guid id))
                return BadRequest($"传入的guid不合法：{guid}");

            var directoryInf = await _directoryService.FindOne(x => x.Id == id);
            if (directoryInf != null)
            {
                var dirFiles = await GetAllFileInDir(guid);

                return this.Json(new { directoryInf, dirFiles });
            }
            return BadRequest("未找到目录");
        }

        //        /// <summary>
        //        /// 删除指定文件夹及其下文件
        //        /// </summary>
        //        /// <returns></returns>
        //        [HttpDelete]
        //        public async Task<IActionResult> DeleteDirectory(string guid)
        //        {
        //            if (!Guid.TryParse(guid, out Guid id))
        //                return BadRequest($"传入的guid不合法：{guid}");

        //            var directoryInf = await _directoryService.FindOne(x => x.Id == id);
        //            if (directoryInf == null)
        //                throw new Exception("未找到文件夹");

        //            var dirFiles = await GetAllFileInDir(guid, false);

        //#pragma warning disable CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法
        //            FileOperateHelper.TryDeleteDirectory(finalDir, true);//异步删除，无需等待
        //#pragma warning restore CS4014 // 由于此调用不会等待，因此在调用完成前将继续执行当前方法

        //            return this.Json(new { directoryInf, dirFiles });


        //        }
        #endregion

        #region 工具代码
        /// <summary>
        /// 获取所有在指定顶级文件夹下的文件（如果发生映射重复文件也带出来，尽可能带出文件）
        /// </summary>
        /// <param name="topDirGuid">顶级目录唯一标识</param>
        /// <returns></returns>
        private async Task<TEntityPaged<CompleteFileResult>> GetAllFileInDir(string topDirGuid)
        {
            var result = new List<CompleteFileResult>();
            var dirReflectFiles = await _reflectfileService.FindAll(x => x.AbstractTopDirGuid == topDirGuid);//映射文件集合
            var dirReflectFilesPIDs = dirReflectFiles.Select(x => x.PId);//映射文件对应的原文件GUID集合
            var sourceFiles = await _fileService.FindAll(x => dirReflectFilesPIDs.Contains(x.Id));//映射文件对应的原始文件集合
                                                                                                  //TODO：可能还需要去重？暂时先不管
            foreach (var dirReflectFile in dirReflectFiles)
            {
                /*
                 * 将映射文件与原始文件信息合并，
                 * 主要修改文件名，虚拟顶级目录，虚拟子目录，上传时间信息，后缀名
                 * 最后添加到dirFiles中，以便后续进行文件打包处理
                 */

                var sourceFile = sourceFiles.FirstOrDefault(x => x.Id == dirReflectFile.PId);
                if (sourceFile == null)
                    throw new Exception($"发生错误：guid为{dirReflectFile.Id}，名称为{dirReflectFile.Name}的映射文件对应的原始文件(guid为：{dirReflectFile.PId})被删除，请联系管理员处理！");

                result.Add(new CompleteFileResult
                {
                    Id = dirReflectFile.Id,
                    AbstractDirPath = dirReflectFile.AbstractDirPath,
                    AbstractTopDirGuid = dirReflectFile.AbstractTopDirGuid,
                    Extension = dirReflectFile.Extension,
                    Keep = dirReflectFile.Keep,
                    Name = dirReflectFile.Name,
                    UploadTime = dirReflectFile.UploadTime,
                    PId = sourceFile.Id,
                    DirPath = sourceFile.DirPath,
                    FileSize = sourceFile.FileSize,
                    MimeType = sourceFile.MimeType,
                    Md5 = sourceFile.Md5,
                });
            }

            return new TEntityPaged<CompleteFileResult>
            {
                Datas = result,
                Total = result.Count
            };
        }
        #endregion
    }
}
